#!/usr/bin/env python3
"""
HTTP服务看门狗程序 - 多项目监控版
为每个在配置文件中定义的服务启动一个独立的监控线程。
"""

import requests
import time
import logging
import subprocess
import sys
import os
import json
import threading
from datetime import datetime
import argparse

# 创建日志目录（如果不存在）
log_dir = '/var/log/service-watchdog'
if not os.path.exists(log_dir):
    os.makedirs(log_dir)

class ServiceWatchdog(threading.Thread):
    def __init__(self, service_config, global_config):
        """
        初始化单个服务的看门狗

        Args:
            service_config (dict): 单个服务的配置 (name, url)
            global_config (dict): 全局配置 (check_interval, timeout, max_failures)
        """
        super().__init__()
        self.name = service_config['name']
        self.url = service_config['url']
        
        self.check_interval = global_config.get('check_interval', 10)
        self.timeout = global_config.get('timeout', 2)
        self.max_failures = global_config.get('max_failures', 3)
        
        self.consecutive_failures = 0
        self.is_running = True
        
        # 为每个服务设置独立的日志记录器
        self.setup_logging()

    def setup_logging(self):
        """为每个服务配置独立的日志记录器"""
        log_file = f'/var/log/service-watchdog/{self.name}_watchdog.log'
        self.logger = logging.getLogger(self.name)
        self.logger.setLevel(logging.INFO)
        
        # 防止重复添加处理器
        if not self.logger.handlers:
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            
            # 文件处理器
            fh = logging.FileHandler(log_file)
            fh.setFormatter(formatter)
            self.logger.addHandler(fh)
            
            # 控制台处理器
            sh = logging.StreamHandler(sys.stdout)
            sh.setFormatter(formatter)
            self.logger.addHandler(sh)

    def check_service(self):
        """
        检查单个HTTP地址

        Returns:
            tuple: (是否成功, 详细信息)
        """
        try:
            start_time = time.time()
            response = requests.get(self.url, timeout=self.timeout)
            response_time = round((time.time() - start_time) * 1000, 2)

            if 200 <= response.status_code < 400:
                return True, f"状态码: {response.status_code}, 响应时间: {response_time}ms"
            else:
                return False, f"异常状态码: {response.status_code}, 响应时间: {response_time}ms"
        
        except requests.exceptions.RequestException as e:
            return False, f"请求异常: {str(e)}"
        except Exception as e:
            return False, f"未知错误: {str(e)}"

    def restart_service(self):
        """重启系统服务"""
        try:
            self.logger.info(f"正在重启服务: {self.name}")
            result = subprocess.run(
                ['systemctl', 'restart', self.name],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                universal_newlines=True,
                timeout=60
            )
            if result.returncode == 0:
                self.logger.info(f"服务重启成功: {self.name}")
                return True
            else:
                self.logger.error(f"服务重启失败: {self.name}")
                self.logger.error(f"错误输出: {result.stderr}")
                return False
        except subprocess.TimeoutExpired:
            self.logger.error(f"服务重启超时: {self.name}")
            return False
        except Exception as e:
            self.logger.error(f"重启服务时发生未知错误: {str(e)}")
            return False

    def run(self):
        """运行看门狗主循环"""
        self.logger.info(f"看门狗启动 - 监控项目: {self.name} ({self.name})")
        self.logger.info(f"监控URL: {self.url}")
        self.logger.info(f"检查间隔: {self.check_interval}s, 超时: {self.timeout}s, 最大失败: {self.max_failures}")

        while self.is_running:
            try:
                success, detail = self.check_service()
                
                if success:
                    self.logger.info(f"✓ {self.url} - {detail}")
                    if self.consecutive_failures > 0:
                        self.logger.info("服务恢复正常，重置失败计数")
                    self.consecutive_failures = 0
                else:
                    self.logger.error(f"✗ {self.url} - {detail}")
                    self.consecutive_failures += 1
                    self.logger.warning(f"服务异常，连续失败次数: {self.consecutive_failures}/{self.max_failures}")

                    if self.consecutive_failures >= self.max_failures:
                        self.logger.warning(f"达到最大失败次数，准备重启服务: {self.name}")
                        if self.restart_service():
                            self.consecutive_failures = 0
                            self.logger.info("服务重启成功，等待60秒后继续检查")
                            time.sleep(60)
                        else:
                            self.logger.error("服务重启失败，将继续监控")
                
                time.sleep(self.check_interval)

            except KeyboardInterrupt:
                self.stop()
            except Exception as e:
                self.logger.error(f"看门狗运行时发生错误: {str(e)}")
                time.sleep(self.check_interval)

    def stop(self):
        """停止看门狗"""
        if self.is_running:
            self.is_running = False
            self.logger.info(f"看门狗已停止 - {self.name}")

def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='多项目HTTP服务看门狗程序')
    parser.add_argument('--config', default='config.json', help='配置文件路径 (默认: config.json)')
    args = parser.parse_args()

    # 设置全局日志
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler('/var/log/service_watchdog_main.log'),
            logging.StreamHandler(sys.stdout)
        ]
    )
    main_logger = logging.getLogger("Main")

    # 加载配置
    try:
        with open(args.config, 'r') as f:
            config = json.load(f)
        main_logger.info(f"从 {args.config} 加载配置成功")
    except Exception as e:
        main_logger.error(f"加载配置文件失败: {str(e)}")
        sys.exit(1)

    services_to_watch = config.get('services', [])
    if not services_to_watch:
        main_logger.error("错误: 配置文件中未找到 'services' 列表")
        sys.exit(1)

    global_config = {
        "check_interval": config.get("check_interval", 10),
        "timeout": config.get("timeout", 2),
        "max_failures": config.get("max_failures", 3)
    }

    watchdogs = []
    for service_config in services_to_watch:
        if all(k in service_config for k in ['name', 'url']):
            watchdog = ServiceWatchdog(service_config, global_config)
            watchdogs.append(watchdog)
            watchdog.start()
        else:
            main_logger.error(f"服务配置不完整，已跳过: {service_config}")

    if not watchdogs:
        main_logger.error("没有有效的服务可以监控，程序退出")
        sys.exit(1)

    main_logger.info(f"已启动 {len(watchdogs)} 个服务监控线程")

    try:
        # 保持主线程运行，直到接收到中断信号
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        main_logger.info("收到中断信号，正在停止所有看门狗...")
        for watchdog in watchdogs:
            watchdog.stop()
        for watchdog in watchdogs:
            watchdog.join() # 等待所有线程结束
        main_logger.info("所有看门狗已停止，程序退出")

if __name__ == "__main__":
    main()